package com.example.autocode.strategy;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.autocode.entity.AutoCodePart;
import com.example.autocode.entity.AutoCodeResult;
import com.example.autocode.enums.CycleMethodEnum;
import com.example.autocode.AutoCodeUtil;
import com.example.autocode.service.IAutoCodeResultService;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @Author zhangxin
 * @create 2021/12/23 16:49
 */
@Component
@Order(4)
public class PartType04Handle implements PartTypeTemplate {

    @Autowired
    private IAutoCodeResultService autoCodeResultService;

    @Override
    public String partHandle(AutoCodePart autoCodePart) {
        // 流水号循环
        if ("1".equals(autoCodePart.getIsSerialCycle())) {
            return serialCycleY(autoCodePart);
        } else {
            return serialCycleN(autoCodePart);
        }
    }

    /**
     * 分段循环
     *
     * @return
     */
    private String serialCycleY(AutoCodePart autoCodePart) {
        // 分段循环方式
        String cycleMethod = autoCodePart.getCycleMethod();

        String param = "";
        if (CycleMethodEnum.CYCLE_METHOD_INPUT.getCode().equals(cycleMethod)) {
            param = autoCodePart.getInputCharacter();
        } else {
            switch (CycleMethodEnum.getByCode(cycleMethod)) {
                case CYCLE_METHOD_YEAR:
                    param = DateUtil.format(LocalDateTime.now(), "yyyy");
                    break;
                case CYCLE_METHOD_MONTH:
                    param = DateUtil.format(LocalDateTime.now(), "yyyyMM");
                    break;
                case CYCLE_METHOD_DAY:
                    param = DateUtil.format(LocalDateTime.now(), "yyyyMMdd");
                    break;
                case CYCLE_METHOD_HOUR:
                    param = DateUtil.format(LocalDateTime.now(), "yyyyMMddHH");
                    break;
                case CYCLE_METHOD_MINUTE:
                    param = DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmm");
                    break;
                default:
                    break;
            }
        }

        List<AutoCodeResult> autoCodeResults = getCodeResult(autoCodePart.getParentCode(), param, cycleMethod);

        // 存在，则无需重新编码，并且结果做修改
        if (CollectionUtil.isNotEmpty(autoCodeResults)) {
            AutoCodeUtil.threadLocal.set(false);
            Integer lastSerialNumber = autoCodeResults.get(0).getLastSerialNumber();
            return String.format("%0" + autoCodePart.getPartLength() + "d", lastSerialNumber + autoCodePart.getSerialStep());
        } else {
            AutoCodeUtil.threadLocal.set(true);
            return String.format("%0" + autoCodePart.getPartLength() + "d", autoCodePart.getSerialStartNo());
        }
    }

    /**
     * 不分段循环
     *
     * @return
     */
    private String serialCycleN(AutoCodePart autoCodePart) {
        List<AutoCodeResult> codeResult = getCodeResult(autoCodePart.getParentCode(), "", "");
        //判断是否存在流水号值，没有则取起始值，有则取当前值+步长
        if (CollectionUtil.isEmpty(codeResult)) {
            AutoCodeUtil.threadLocal.set(true);
            return String.format("%0" + autoCodePart.getPartLength() + "d", autoCodePart.getSerialStartNo());
        } else {
            AutoCodeUtil.threadLocal.set(false);
            return String.format("%0" + autoCodePart.getPartLength() + "d", codeResult.get(0).getLastSerialNumber() + autoCodePart.getSerialStep());
        }
    }

    /**
     * 根据循环方式 查询编码结果中是否存在循环数据
     * @param parentCode 编码器code
     * @param param 参数
     * @param cycleMethod 循环方式
     * @return
     */
    private List<AutoCodeResult> getCodeResult(String parentCode, String param, String cycleMethod) {
        LambdaQueryWrapper<AutoCodeResult> queryWrapper = Wrappers.<AutoCodeResult>lambdaQuery()
                .eq(AutoCodeResult::getParentCode, parentCode)
                .eq(StringUtils.equals(cycleMethod, CycleMethodEnum.CYCLE_METHOD_INPUT.getCode()), AutoCodeResult::getLastInputChar, param)
                .likeRight(equalsAny(cycleMethod, CycleMethodEnum.CYCLE_METHOD_YEAR.getCode()
                        , CycleMethodEnum.CYCLE_METHOD_MONTH.getCode()
                        , CycleMethodEnum.CYCLE_METHOD_DAY.getCode()
                        ,CycleMethodEnum.CYCLE_METHOD_HOUR.getCode()
                        ,CycleMethodEnum.CYCLE_METHOD_MINUTE.getCode()), AutoCodeResult::getGenerateDate, param);
        List<AutoCodeResult> list = autoCodeResultService.list(queryWrapper);
        return list;
    }

    public static boolean equalsAny(CharSequence string, CharSequence... searchStrings)
    {
        if (ArrayUtils.isNotEmpty(searchStrings)) {
            for (CharSequence next : searchStrings) {
                if (StringUtils.equals(string, next)) {
                    return true;
                }
            }
        }
        return false;
    }
}
